#include "Hardware/I2C.h"
#include "Hardware/Timer.h"

#define IIC P2
#define SDAPort (0)
#define SCLPort (1)

#define SDA(x) ((!!(x))?SetBit(IIC,SDAPort) : ClrBit(IIC,SDAPort));Delay5us()
#define SCL(x) ((!!(x))?SetBit(IIC,SCLPort) : ClrBit(IIC,SCLPort));Delay5us()

//I2C 全部高电平初始化
void I2CInit()
{
	SDA(1);
	SCL(1);
}

//SCL==高电平,SDA由高电平下降到低电平表示起始信号
void I2CStart()
{
	I2CInit();
	SDA(1);
	SCL(1);
	SDA(0);
}

//SCL==高电平,SDA由低电平升到高电平表示结束信号
void I2CStop()
{
	SDA(0);
	SCL(1);
	SDA(1);
	Delay(5); //延时5毫秒 以便下次操作
}

//主机应答
//参数 isACK, isACK==true表示应答,false表示非应答
void MasterACK(bool isACK)
{
	SCL(0); //SCL低电平,SDA数据可变
	SDA(!isACK); //应答 低电平有效,高电平无效,所以取反
	SCL(1); //SCL高电平,从机读走SDA数据
	
	//释放总线
	SCL(0);
	SDA(1);
}

//从机应答
//返回值 == true 表示 从机应答,false表示 从机非应答
bool TestACK()
{
	SCL(1); //SCL高电平,SDA数据稳定可读有效
	if(GetBit(IIC,SDAPort)) //==1 表示 未应答
	{
		SCL(0);
		I2CStop(); //停止
		return false;
	}
	else
	{
		SCL(0);
		return true;
	}
}

//内部:发送一个字节
void SendByte(byte dat)
{
	int8 i;
	for(i=sizeof(byte)*8-1;i>=0;--i)
	{
		SCL(0); //SCL低电平,数据可以变化
		SDA( GetBit(dat,i) ); //从最高位依次发送
		SCL(1); //SCL高电平,数据被从机读走
	}
	//释放总线
	SCL(0);
	SDA(1);
}

//内部:接收一个字节
byte RecvByte()
{
	byte dat=0;
	int8 i;
	//要求从机释放总线
	SCL(0);
	SDA(1);
	
	for(i=sizeof(byte)*8-1;i>=0;--i)
	{
		SCL(1); //高电平,读入数据
		if(GetBit(IIC,SDAPort))
			SetBit(dat,i);
		SCL(0); //允许数据变化(从机)
	}
	
	return dat;
}

bool I2CSendByte(uint8 deviceAddr,uint8 innerAddr,byte dat)
{
	I2CStart();
	SendByte(deviceAddr+0); //送从机地址,+0表示从主机写地址
	if(!TestACK())
	{
		goto FAIL;
	}
	
	SendByte(innerAddr); //送内部地址
	if(!TestACK())
	{
		goto FAIL;
	}
	
	SendByte(dat);
	if (!TestACK())
	{
		goto FAIL;
	}
	I2CStop();
	return true;
FAIL:
	I2CStop();
	return false;
}

bool I2CRecvByte(uint8 deviceAddr,uint8 innerAddr,byte* dat)
{
	if(dat==NULL)
	{
		return false;
	}
	I2CStart();
	SendByte(deviceAddr+0);//送从机地址,+0表示从主机写地址
	if(!TestACK())
	{
		goto FAIL;
	}
	SendByte(innerAddr);
	MasterACK(false); //应不应答都行
	
	
	I2CStart(); 
	SendByte(deviceAddr+1); //送从机地址,+1表示从从机读数据
	if(!TestACK())
	{
		goto FAIL;
	}
	*dat=RecvByte();
	MasterACK(false);
	I2CStop();
	return true;
FAIL:
	I2CStop();
	return false;
}